#include "mediakeys.h"

namespace {
  const QString DBUS_MUSIC_SERVICE("com.nokia.music-suite");
  const QString DBUS_MUSIC_PATH("/");
  const QString DBUS_MUSIC_INTERFACE("com.nokia.maemo.meegotouch.MusicSuiteInterface");

  const QString DBUS_PBSTATE("playbackState");
  const QString DBUS_PREVIOUS("previous");
  const QString DBUS_NEXT("next");
  const QString DBUS_PAUSE("pausePlayback");
  const QString DBUS_RESUME("resumePlayback");

  const QString DBUS_MAFW_SERVICE("com.nokia.mafw.plugin.libqmafw_gst_renderer_plugin");
  const QString DBUS_MAFW_PATH("/com/nokia/mafw/renderer/mafw_gst_renderer");
  const QString DBUS_MAFW_INTERFACE("com.nokia.mafw.extension");

  const QString DBUS_MAFW_GETPROPERTY("get_extension_property");
  const QString DBUS_MAFW_SETPROPERTY("set_extension_property");


  const QString GCONF_VALUE_PLAYPAUSE("playpause");
  const QString GCONF_VALUE_PREVIOUS("previous");
  const QString GCONF_VALUE_NEXT("next");

  const QString MSG_RES_ACQUIRED = "Media keys";
  const QString MSG_RES_RELEASED = "Volume keys";
  const QString MSG_RES_DENIED   = "Resource denied";
}


MediaKeys::MediaKeys(QObject *parent) : QObject(parent)
{
    volumeUpPressed   = false;
    volumeDownPressed = false;
    onNextKeyReleased = false;

    useLongPress = true;
    volumeStep = 4;
    longPressDuration = 1000;

    hwkeys = new MeeGo::QmKeys(this);
    connect(hwkeys, SIGNAL (keyEvent (MeeGo::QmKeys::Key, MeeGo::QmKeys::State)),
            this,   SLOT   (keyEvent (MeeGo::QmKeys::Key, MeeGo::QmKeys::State)) );

    volResourceSet = new ResourcePolicy::ResourceSet("player", this);
    volResourceSet->setAlwaysReply();
    volResourceSet->addResourceObject(new ResourcePolicy::ScaleButtonResource);

    connect(volResourceSet, SIGNAL(lostResources()), this, SLOT(keyResourceReleased()));
    connect(volResourceSet, SIGNAL(resourcesReleased()), this, SLOT(keyResourceReleased()));
    connect(volResourceSet, SIGNAL(resourcesGranted(QList<ResourcePolicy::ResourceType>)),
            this, SLOT(keyResourceAcquired()));
}


// HW KEYS EVENTS SLOT
void MediaKeys::keyEvent(MeeGo::QmKeys::Key key, MeeGo::QmKeys::State state)
{
    // Key pressed
    if (state == MeeGo::QmKeys::KeyDown) {
        if (key==MeeGo::QmKeys::VolumeUp) {
            if (!volumeUpPressed) {
                volUpTime.start();
                volumeUpPressed = true;
            }
        }
        else if (key==MeeGo::QmKeys::VolumeDown) {
            if (!volumeDownPressed) {
                volDownTime.start();
                volumeDownPressed = true;
            }
        }
        return;
    }
    // Key released
    else if (state == MeeGo::QmKeys::KeyUp) {

        // VolumeUp Released
        if(key==MeeGo::QmKeys::VolumeUp) {
            volumeUpPressed = false;

            // ResourceSet acquired
            if (volResourceSet->hasResourcesGranted()) {
                if (volumeDownPressed) {
                    onNextKeyReleased = true;
                }
                else if (onNextKeyReleased) {
                    volResourceSet->release();
                    onNextKeyReleased=false;
                }
//                else if (isMusicSuiteServiceRegistered()) {
                else if (!useLongPress || (useLongPress && volUpTime.elapsed() > longPressDuration) ) {
                    switch (volUpAction) {
                    case PlayPause:
                        togglePlayback(); break;
                    case Previous:
                        previous(); break;
                    case Next:
                        next(); break;
                    }
                } else {
                    increaseVolume();
                }

            // ResourceSet not acquired
            } else {
                if (volumeDownPressed) {
                    onNextKeyReleased=true;
                }
                else if (onNextKeyReleased) {
                    volResourceSet->acquire();
                    onNextKeyReleased=false;
                }
            }
        }

        // VolumeDown released
        else if (key==MeeGo::QmKeys::VolumeDown) {
            volumeDownPressed = false;

            // ResourceSet is acquired
            if (volResourceSet->hasResourcesGranted()) {
                if (volumeUpPressed) {
                    onNextKeyReleased = true;
                }
                else if (onNextKeyReleased) {
                    volResourceSet->release();
                    onNextKeyReleased = false;
                }
//                else if (isMusicSuiteServiceRegistered()) {
                else if (!useLongPress || (useLongPress && volDownTime.elapsed() > longPressDuration) ) {
                    switch (volDownAction) {
                    case PlayPause:
                        togglePlayback(); break;
                    case Previous:
                        previous(); break;
                    case Next:
                        next(); break;
                    }
                } else {
                    decreaseVolume();
                }

            // ResourceSet not acquired
            } else {
                if (volumeUpPressed) {
                    onNextKeyReleased=true;
                }
                else if (onNextKeyReleased) {
                    volResourceSet->acquire();
                    onNextKeyReleased=false;
                }
            }
        }
    }
}




// VOLUME KEYS RESOURCE SLOTS

void MediaKeys::keyResourceAcquired() {
    if (gconfStatus) {
        if (gconfStatus->value().toBool()) return;
        gconfStatus->setValue(true);
    }

    MNotification notification(MNotification::DeviceEvent, "", MSG_RES_ACQUIRED);
    notification.setImage("icon-m-common-done");
    notification.publish();
}

void MediaKeys::keyResourceReleased() {
    if (gconfStatus) {
        if (!gconfStatus->value().toBool()) return;
        gconfStatus->setValue(false);
    }

    MNotification notification(MNotification::DeviceEvent, "", MSG_RES_RELEASED);
    notification.setImage("icon-m-common-done");
    notification.publish();
}

void MediaKeys::keyResourceDenied() {
    MNotification notification(MNotification::DeviceEvent, "", MSG_RES_DENIED);
    notification.setImage("icon-m-transfer-error");
    notification.publish();
}



// DBUS METHOD CALLS

bool MediaKeys::isMusicSuiteServiceRegistered() {
    QDBusConnectionInterface *interface = QDBusConnection::sessionBus().interface();
    QDBusReply<bool> reply = interface->isServiceRegistered(DBUS_MUSIC_SERVICE);
    if (reply.isValid())
        return reply.value();
    else
        return false;
}

bool MediaKeys::playbackState() {
    QDBusInterface dbus_iface(DBUS_MUSIC_SERVICE, DBUS_MUSIC_PATH, DBUS_MUSIC_INTERFACE);
    QDBusReply<int> reply = dbus_iface.call(DBUS_PBSTATE);
    if (reply.isValid())
        if (reply.value()==1)
            return true;
    // when reply.value()==0 || reply.value()==2
    return false;
}

void MediaKeys::previous() {
    QDBusInterface dbus_iface(DBUS_MUSIC_SERVICE, DBUS_MUSIC_PATH, DBUS_MUSIC_INTERFACE);
    dbus_iface.call(DBUS_PREVIOUS);
}

void MediaKeys::next() {
    QDBusInterface dbus_iface(DBUS_MUSIC_SERVICE, DBUS_MUSIC_PATH, DBUS_MUSIC_INTERFACE);
    dbus_iface.call(DBUS_NEXT);
}

void MediaKeys::togglePlayback() {
    QDBusInterface dbus_iface(DBUS_MUSIC_SERVICE, DBUS_MUSIC_PATH, DBUS_MUSIC_INTERFACE);
    if (playbackState())
        dbus_iface.call(DBUS_PAUSE);
    else
        dbus_iface.call(DBUS_RESUME);
}



bool MediaKeys::increaseVolume() {
    QDBusInterface dbus_iface(DBUS_MAFW_SERVICE, DBUS_MAFW_PATH, DBUS_MAFW_INTERFACE);
    // get current volume
    QDBusMessage reply = dbus_iface.call(DBUS_MAFW_GETPROPERTY, "volume");
    if(reply.type() == QDBusMessage::ErrorMessage)
        return false;
    QDBusVariant v = reply.arguments().at(1).value<QDBusVariant>();
    uint volume = v.variant().toUInt();

    uint newvolume = volume + volumeStep;
    if(newvolume > 100)
        newvolume = 100;

    QDBusReply<bool> r = dbus_iface.call(DBUS_MAFW_SETPROPERTY, "volume", QVariant::fromValue(QDBusVariant(newvolume)));
    return r.value();
}

bool MediaKeys::decreaseVolume() {
    QDBusInterface dbus_iface(DBUS_MAFW_SERVICE, DBUS_MAFW_PATH, DBUS_MAFW_INTERFACE);

    QDBusMessage reply = dbus_iface.call("get_extension_property", "volume");
    if(reply.type() == QDBusMessage::ErrorMessage)
        return false;
    QDBusVariant v = reply.arguments().at(1).value<QDBusVariant>();
    uint volume = v.variant().toUInt();

    uint newvolume = volume - volumeStep;
    if(newvolume > volume)
        newvolume = 0;

    QDBusReply<bool> r = dbus_iface.call("set_extension_property", "volume", QVariant::fromValue(QDBusVariant(newvolume)));
    return r.value();
}





// SETTERS FOR GCONF ITEMS

void MediaKeys::setGconfUpAction(GConfItemQmlProxy * item) {
    gconfUpAction = item;
    connect(gconfUpAction, SIGNAL(valueChanged()), this, SLOT(updateUpAction()));
    updateUpAction();
}

void MediaKeys::setGconfDownAction(GConfItemQmlProxy * item) {
    gconfDownAction = item;
    connect(gconfDownAction, SIGNAL(valueChanged()), this, SLOT(updateDownAction()));
    updateDownAction();
}

void MediaKeys::setGconfStatus(GConfItemQmlProxy * item) {
    gconfStatus = item;
    connect(gconfStatus, SIGNAL(valueChanged()), this, SLOT(updateStatus()));
    updateStatus();
}

void MediaKeys::setGconfLongPress(GConfItemQmlProxy * item) {
    gconfLongPress = item;
    connect(gconfLongPress, SIGNAL(valueChanged()), this, SLOT(updateLongPress()));
    updateLongPress();
}

void MediaKeys::setGconfPressDuration(GConfItemQmlProxy * item) {
    gconfPressDuration = item;
    connect(gconfPressDuration, SIGNAL(valueChanged()), this, SLOT(updatePressDuration()));
    updatePressDuration();
}

// GCONF SLOTS

void MediaKeys::updateStatus() {
    QVariant value = gconfStatus->value();
    if (value.toBool())
        volResourceSet->acquire();
    else
        volResourceSet->release();
}

void MediaKeys::updateUpAction() {
    QVariant value = gconfUpAction->value();
    if(value == GCONF_VALUE_PLAYPAUSE)
        volUpAction = PlayPause;
    else if(value == GCONF_VALUE_NEXT)
        volUpAction = Next;
    else
        volUpAction = Previous;
}

void MediaKeys::updateDownAction() {
    QVariant value = gconfDownAction->value();
    if(value == GCONF_VALUE_PLAYPAUSE)
        volDownAction = PlayPause;
    else if(value == GCONF_VALUE_PREVIOUS)
        volDownAction = Previous;
    else
        volDownAction = Next;
}

void MediaKeys::updateLongPress() {
    QVariant value = gconfLongPress->value();
    useLongPress = value.toBool();
}

void MediaKeys::updatePressDuration() {
    QVariant value = gconfPressDuration->value();
    longPressDuration= value.toInt();
}
